home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / utility / mu17_ext.zip / RLHANDLE.C < prev    next >
C/C++ Source or Header  |  1994-03-07  |  17KB  |  585 lines

  1. /*
  2. **    $VER: rlhandler.c 1.1 (08.02.94)
  3. **
  4. **    rlogin.service handler
  5. **
  6. **    ⌐ Copyright 1994 by Norbert Pⁿschel
  7. **    All Rights Reserved
  8. */
  9.  
  10. #include <proto/exec.h>
  11. #include <proto/dos.h>
  12. #include <proto/utility.h>
  13. #include <proto/multiuser.h>
  14. #include <clib/accounts_protos.h>
  15. #include <pragmas/accounts_pragmas.h>
  16. #include <clib/nipc_protos.h>
  17. #include <pragmas/nipc_pragmas.h>
  18. #include <clib/alib_stdio_protos.h>
  19.  
  20. #include <envoy/errors.h>
  21. #include <exec/alerts.h>
  22. #include <exec/memory.h>
  23. #include <dos/var.h>
  24. #include <dos/dostags.h>
  25. #include <dos/dosextens.h>
  26. #include <devices/conunit.h>
  27.  
  28. #include <string.h>
  29.  
  30. #include <debug.h>
  31.  
  32. #define GVB GVF_LOCAL_ONLY|GVF_BINARY_VAR|GVF_DONT_NULL_TERM
  33.  
  34. #define tp_size sizeof(struct Task *)
  35. #define pp_size sizeof(struct MsgPort *)
  36.  
  37. #define req(trans,n) (void *)(((UBYTE *)(trans->trans_RequestData))+(n))
  38. #define resp(trans,n) (void *)(((UBYTE *)(trans->trans_ResponseData))+(n))
  39.  
  40. #define OFFS_CONUNIT  0
  41. #define SIZE_CONUNIT  14*sizeof(WORD)
  42. #define OFFS_RES1     OFFS_CONUNIT+SIZE_CONUNIT
  43. #define SIZE_RES1     sizeof(LONG)
  44. #define OFFS_RES2     OFFS_RES1+SIZE_RES1
  45. #define SIZE_RES2     sizeof(LONG)
  46. #define OFFS_RESPDATA OFFS_RES2+SIZE_RES2
  47.  
  48. #define OFFS_ARG1     0
  49. #define SIZE_ARG1     sizeof(LONG)
  50. #define OFFS_ARG2     OFFS_ARG1+SIZE_ARG1
  51. #define SIZE_ARG2     sizeof(LONG)
  52. #define OFFS_REQDATA  OFFS_ARG2+SIZE_ARG2
  53.  
  54. #define CONUNIT(ci) (APTR)&(((struct ConUnit *)((ci)->ci_IOStdReq->io_Unit))->cu_XCP)
  55.  
  56. extern volatile ULONG NumProcs;
  57.  
  58. #define CFGBUFFLEN 256
  59. #define CBUFFLEN   2*CFGBUFFLEN+80
  60.  
  61. /* rshell startup packet:
  62.  
  63.    Arg1 = user name
  64.    Arg2 = password
  65.    Arg3 = host name
  66.    Arg4 = handler port
  67.  
  68. */
  69.  
  70. void __saveds rshell_func(void)
  71.  
  72. {
  73.   struct muBase *muBase;
  74.   struct MsgPort *handler_port;
  75.  
  76.   struct FileHandle *fh;
  77.   BPTR bfh;
  78.  
  79.   UBYTE cbuff[CBUFFLEN];
  80.   UBYTE cfg[CFGBUFFLEN];
  81.  
  82.   struct Message *msg;
  83.   struct DosPacket *dp;
  84.  
  85.   Forbid();
  86.   NumProcs++;
  87.   Permit();
  88.  
  89.   handler_port = &(((struct Process *)FindTask(0))->pr_MsgPort);
  90.  
  91.   WaitPort(handler_port);
  92.   msg = GetMsg(handler_port); /* get startup message */
  93.  
  94.   if(msg == 0 || (dp = (struct DosPacket *)(msg->mn_Node.ln_Name)) == 0) {
  95.     Alert(AN_Unknown);
  96.     Wait(0); /* not much that I can do here */
  97.   }
  98.  
  99.   handler_port = (struct MsgPort *)(dp->dp_Arg4);
  100.  
  101.   strcpy(cbuff,"Execute S:Shell-Startup\n");
  102.  
  103.   muBase = (struct muBase *)OpenLibrary(MULTIUSERNAME,MULTIUSERVERSION);
  104.   if(muBase) {
  105.     if(muGetTaskOwner(0)) {
  106.       muLogout(muT_All,TRUE,muT_Quiet,TRUE,TAG_DONE);
  107.     }
  108.     if(Stricmp((STRPTR)(dp->dp_Arg1),"Nobody")) {
  109.       if(muLogin(muT_UserID,(STRPTR)(dp->dp_Arg1),
  110.                  muT_Password,(STRPTR)(dp->dp_Arg2),
  111.                  TAG_DONE)) {
  112.         bfh = muGetConfigDirLock();
  113.         if(bfh) {
  114.           if(NameFromLock(bfh,cfg,CFGBUFFLEN) &&
  115.              AddPart(cfg,muProfile_FileName,CFGBUFFLEN)) {
  116.             strcat(cbuff,"If EXISTS ");
  117.             strcat(cbuff,cfg);
  118.             strcat(cbuff,"\nExecute ");
  119.             strcat(cbuff,cfg);
  120.             strcat(cbuff,"\nEndIf\n");
  121.           }
  122.           UnLock(bfh);
  123.         }
  124.       }
  125.     }
  126.     CloseLibrary((struct Library *)muBase);
  127.   }
  128.  
  129.   fh = 0;
  130.  
  131.   if(SetVar("REMOTE",(STRPTR)(dp->dp_Arg3),-1,0)) {
  132.     fh = (struct FileHandle *)AllocDosObjectTags(DOS_FILEHANDLE,TAG_END);
  133.     if(fh) {
  134.       dp->dp_Res1 = DOSTRUE;
  135.       PutMsg(dp->dp_Port,msg);
  136.  
  137.       fh->fh_Type = handler_port;
  138.       bfh = MKBADDR(fh);
  139.       if(DoPkt3(handler_port,ACTION_FINDOUTPUT,bfh,0,0)) {
  140.         Execute(cbuff,bfh,0);
  141.         DoPkt1(handler_port,ACTION_END,fh->fh_Arg1);
  142.       }
  143.       FreeDosObject(DOS_FILEHANDLE,fh);
  144.     }
  145.   }
  146.   if(fh == 0) {
  147.     dp->dp_Res1 = DOSFALSE;
  148.     dp->dp_Res2 = ENVOYERR_NORESOURCES;
  149.     PutMsg(dp->dp_Port,msg);
  150.   }
  151.   Forbid();
  152.   NumProcs--;
  153. }
  154.  
  155. struct ConInfo {
  156.   struct MinList   ci_Actions;
  157.   LONG             ci_OpenCnt;
  158.   LONG             ci_NextKey;
  159.   struct Entity   *ci_Dest;
  160.   struct Entity   *ci_Source;
  161.   struct MsgPort  *ci_Handler;
  162.   struct MsgPort  *ci_Break;
  163.   struct IOStdReq *ci_IOStdReq;
  164. };
  165.   
  166. void do_packet(struct Library *NIPCBase,
  167.                struct ConInfo *ci,
  168.                struct DosPacket *dp);
  169.  
  170. void do_transaction(struct Library *NIPCBase,
  171.                     struct ConInfo *ci,
  172.                     struct Transaction *trans);
  173.  
  174. /* handler startup packet:
  175.  
  176.    Arg1 = user name
  177.    Arg2 = password
  178.    Arg3 = host name
  179.    Arg4 = entity name buffer
  180.  
  181. */
  182.  
  183. void __saveds handler_func(void)
  184.  
  185. {
  186.   struct Library *NIPCBase;
  187.  
  188.   struct ConInfo ci;
  189.  
  190.   struct Process *rshell;
  191.  
  192.   ULONG entsignum;
  193.   struct Transaction *trans;
  194.  
  195.   struct Message *msg;
  196.   struct DosPacket *dp;
  197.  
  198.   UBYTE uname[32];
  199.   UBYTE pwd[16];
  200.   UBYTE hname[128];
  201.  
  202.   ULONG mask;
  203.  
  204.   Forbid();
  205.   NumProcs++;
  206.   Permit();
  207.  
  208.   ci.ci_Handler = &(((struct Process *)FindTask(0))->pr_MsgPort);
  209.  
  210.   WaitPort(ci.ci_Handler);
  211.   msg = GetMsg(ci.ci_Handler); /* get startup message */
  212.  
  213.   if(msg == 0 || (dp = (struct DosPacket *)(msg->mn_Node.ln_Name)) == 0) {
  214.     Alert(AN_Unknown);
  215.     Wait(0); /* not much that I can do here */
  216.   }
  217.  
  218.   strcpy(uname,(STRPTR)(dp->dp_Arg1));
  219.   strcpy(pwd,(STRPTR)(dp->dp_Arg2));
  220.   strcpy(hname,(STRPTR)(dp->dp_Arg3));
  221.  
  222.   debug("Handler\n");
  223.  
  224.   ci.ci_Source = 0; /* because we use it as flag */
  225.  
  226.   NIPCBase = OpenLibrary("nipc.library",39);
  227.   if(NIPCBase) {
  228.     ci.ci_Handler = CreateMsgPort();
  229.     if(ci.ci_Handler) {
  230.       sprintf((STRPTR)(dp->dp_Arg4),"RHandler_%ld",FindTask(0));
  231.       ci.ci_Source = CreateEntity(ENT_Name,dp->dp_Arg4,
  232.                                   ENT_Public,TRUE,
  233.                                   ENT_AllocSignal,&entsignum,
  234.                                   TAG_DONE);
  235.       if(ci.ci_Source) {   
  236.         debug("Handler Entity created\n"); /* now we have to reply */
  237.         dp->dp_Res1 = DOSTRUE;
  238.         PutMsg(dp->dp_Port,msg);
  239.         debug2("Waiting for Startup-Transaction: %ld\n",entsignum);
  240.         do {
  241.           Wait(1L<<entsignum); /* wait for startup transaction */
  242.           trans = GetTransaction(ci.ci_Source);
  243.         } while(trans == 0);
  244.         if(trans->trans_Command > 1) {
  245.           trans->trans_Error = ENVOYERR_CMDUNKNOWN;
  246.           ci.ci_Dest = 0;
  247.         }
  248.         else {
  249.           if(trans->trans_Command == 1) {
  250.             ci.ci_IOStdReq = (struct IOStdReq *)
  251.               AllocMem(sizeof(struct IOStdReq),MEMF_PUBLIC|MEMF_CLEAR);
  252.             if(ci.ci_IOStdReq) {
  253.               ci.ci_IOStdReq->io_Unit = (struct Unit *)
  254.                 AllocMem(sizeof(struct ConUnit),MEMF_PUBLIC|MEMF_CLEAR);
  255.               if(ci.ci_IOStdReq->io_Unit) {
  256.                 CopyMem(req(trans,OFFS_CONUNIT),CONUNIT(&ci),SIZE_CONUNIT);
  257.               }
  258.               else {
  259.                 FreeMem(ci.ci_IOStdReq,sizeof(struct IOStdReq));
  260.                 ci.ci_IOStdReq = 0;
  261.               }
  262.             }
  263.           }
  264.           else ci.ci_IOStdReq = 0;
  265.  
  266.           debug2("IOStdReq: %ld\n",(LONG)(ci.ci_IOStdReq));
  267.           ci.ci_Dest = FindEntity(*hname ? hname : 0,
  268.             (STRPTR)req(trans,SIZE_CONUNIT),ci.ci_Source,
  269.             &(trans->trans_Error));
  270.         }
  271.  
  272.         ReplyTransaction(trans);
  273.  
  274.         if(ci.ci_Dest) {
  275.           debug("Remote Entity detected\n");
  276.           rshell = CreateNewProcTags(NP_Entry,rshell_func,
  277.                                      NP_Name,"Remote Shell Executor",
  278.                                      NP_Priority,0,
  279.                                      NP_WindowPtr,-1,
  280.                                      NP_Cli,TRUE,
  281.                                      TAG_DONE);    
  282.           if(rshell) {
  283.             debug("Remote Shell Created\n");
  284.             if(DoPkt4(&(rshell->pr_MsgPort),0,(LONG)uname,(LONG)pwd,
  285.                (LONG)hname,(LONG)ci.ci_Handler)) {
  286.               NewList((struct List *)&(ci.ci_Actions));
  287.               ci.ci_OpenCnt = 0;
  288.               ci.ci_NextKey = 0;
  289.               ci.ci_Break = &(rshell->pr_MsgPort);
  290.               debug("Starting Loop\n");
  291.               mask = (1L<<ci.ci_Handler->mp_SigBit)|(1L<<entsignum);
  292.     
  293.               do {
  294.                 Wait(mask);
  295.                 do {
  296.                   if(trans = GetTransaction(ci.ci_Source)) {
  297.                     do_transaction(NIPCBase,&ci,trans);
  298.                   }
  299.                   if(msg = GetMsg(ci.ci_Handler)) {
  300.                     dp = (struct DosPacket *)(msg->mn_Node.ln_Name);
  301.                     do_packet(NIPCBase,&ci,dp);
  302.                   }
  303.                 } while(msg != 0 || trans != 0);
  304.               } while(ci.ci_OpenCnt > 0 ||
  305.                       !IsListEmpty((struct List *)&(ci.ci_Actions)));
  306.               debug("Ending Loop\n");
  307.               trans = AllocTransaction(TAG_DONE);
  308.               if(trans) {
  309.                 trans->trans_Command = 1;
  310.                 DoTransaction(ci.ci_Dest,ci.ci_Source,trans);
  311.                 FreeTransaction(trans);
  312.               }
  313.             }
  314.           }
  315.           LoseEntity(ci.ci_Dest);
  316.         }
  317.         if(ci.ci_IOStdReq) {
  318.           if(ci.ci_IOStdReq->io_Unit) {
  319.             FreeMem(ci.ci_IOStdReq->io_Unit,sizeof(struct ConUnit));
  320.           }
  321.           FreeMem(ci.ci_IOStdReq,sizeof(struct IOStdReq));
  322.         }
  323.         DeleteEntity(ci.ci_Source);
  324.       }
  325.       DeleteMsgPort(ci.ci_Handler);
  326.     }
  327.     CloseLibrary(NIPCBase);
  328.   }
  329.   debug("Ending Handler\n");
  330.   if(ci.ci_Source == 0) {
  331.     dp->dp_Res1 = DOSFALSE;
  332.     dp->dp_Res2 = ENVOYERR_NORESOURCES;
  333.     PutMsg(dp->dp_Port,msg);
  334.   }
  335.   Forbid();
  336.   NumProcs--;
  337. }
  338.  
  339. struct ActionNode {
  340.   struct MinNode      an_Node;
  341.   struct DosPacket   *an_Packet;
  342.   struct Transaction *an_Trans;
  343. };
  344.  
  345. void do_packet(struct Library *NIPCBase,
  346.                struct ConInfo *ci,
  347.                struct DosPacket *dp)
  348.  
  349. {
  350.   struct ActionNode *an;
  351.   struct Transaction *trans;
  352.   struct FileHandle *fh;
  353.   struct MsgPort *rport;
  354.   LONG temp;
  355.  
  356.   debug2("Received Packet: %ld\n",dp->dp_Type);
  357.  
  358.   switch(dp->dp_Type) {
  359.     case ACTION_FINDUPDATE:
  360.     case ACTION_FINDINPUT:
  361.     case ACTION_FINDOUTPUT:
  362.       fh = BADDR(dp->dp_Arg1);
  363.       fh->fh_Port = (struct MsgPort *)DOSTRUE;
  364.       fh->fh_Arg1 = ci->ci_NextKey++;
  365.       ci->ci_OpenCnt++;
  366.       dp->dp_Res1 = DOSTRUE;
  367.       ci->ci_Break = dp->dp_Port;
  368.       dp->dp_Port = ci->ci_Handler;
  369.       PutMsg(ci->ci_Break,dp->dp_Link);
  370.       debug2("Open: %d\n",ci->ci_OpenCnt);
  371.       return;
  372.     case ACTION_END:
  373.       debug2("Close: %ld\n",dp->dp_Arg1);
  374.       an = (struct ActionNode *)(ci->ci_Actions.mlh_Head);
  375.       while(an->an_Node.mln_Succ) {
  376.         temp = an->an_Packet->dp_Type;
  377.         if(temp != ACTION_SCREEN_MODE && temp != ACTION_WAIT_CHAR &&
  378.            an->an_Packet->dp_Arg1 == dp->dp_Arg1) {
  379.           AbortTransaction(an->an_Trans);
  380.           WaitTransaction(an->an_Trans);
  381.           FreeTransaction(an->an_Trans);
  382.           if(temp == ACTION_READ || temp == ACTION_WRITE) {
  383.             an->an_Packet->dp_Res1 = -1;
  384.           }
  385.           else {
  386.             an->an_Packet->dp_Res1 = DOSFALSE;
  387.           }
  388.           an->an_Packet->dp_Res2 = ERROR_INVALID_LOCK;
  389.           rport = an->an_Packet->dp_Port;
  390.           an->an_Packet->dp_Port = ci->ci_Handler;
  391.           PutMsg(rport,an->an_Packet->dp_Link);
  392.           temp = (LONG)(an->an_Node.mln_Succ);
  393.           Remove((struct Node *)an);
  394.           FreeMem(an,sizeof(struct ActionNode));
  395.           an = (struct ActionNode *)temp;
  396.         }
  397.         else {
  398.           an = (struct ActionNode *)(an->an_Node.mln_Succ);
  399.         }
  400.       }
  401.       ci->ci_OpenCnt--;
  402.       dp->dp_Res1 = DOSTRUE;
  403.       rport = dp->dp_Port;
  404.       dp->dp_Port = ci->ci_Handler;
  405.       PutMsg(rport,dp->dp_Link);
  406.       return;
  407.     case ACTION_READ:
  408.       an = (struct ActionNode *)AllocMem(sizeof(struct ActionNode),0);
  409.       if(an) {
  410.         trans = AllocTransaction(TRN_AllocReqBuffer,
  411.                                  OFFS_REQDATA,
  412.                                  TRN_AllocRespBuffer,
  413.                                  OFFS_RESPDATA+dp->dp_Arg3,
  414.                                  TAG_DONE);    
  415.         if(trans) {
  416.           *(LONG *)req(trans,OFFS_ARG1) = ACTION_READ;
  417.           *(LONG *)req(trans,OFFS_ARG2) = dp->dp_Arg3;
  418.           BeginTransaction(ci->ci_Dest,ci->ci_Source,trans);
  419.           an->an_Trans = trans;
  420.           an->an_Packet = dp;
  421.           AddTail((struct List *)&(ci->ci_Actions),(struct Node *)an);
  422.           return;
  423.         }
  424.         FreeMem(an,sizeof(struct ActionNode));
  425.       }
  426.       dp->dp_Res1 = -1;
  427.       goto nomem2;
  428.     case ACTION_WRITE:
  429.     case 2001: /* ACTION_FORCE */
  430.     case 2002: /* ACTION_STACK */
  431.     case 2003: /* ACTION_QUEUE */
  432.       an = (struct ActionNode *)AllocMem(sizeof(struct ActionNode),0);
  433.       if(an) {
  434.         trans = AllocTransaction(TRN_AllocReqBuffer,
  435.                                  OFFS_REQDATA+dp->dp_Arg3,
  436.                                  TRN_AllocRespBuffer,
  437.                                  OFFS_RESPDATA,
  438.                                  TAG_DONE);    
  439.         if(trans) {
  440.           *(LONG *)req(trans,OFFS_ARG1) = dp->dp_Type;
  441.           *(LONG *)req(trans,OFFS_ARG2) = dp->dp_Arg3;
  442.           CopyMem((APTR)(dp->dp_Arg2),req(trans,OFFS_REQDATA),dp->dp_Arg3);
  443.           BeginTransaction(ci->ci_Dest,ci->ci_Source,trans);
  444.           an->an_Trans = trans;
  445.           an->an_Packet = dp;
  446.           AddTail((struct List *)&(ci->ci_Actions),(struct Node *)an);
  447.           return;
  448.         }
  449.         FreeMem(an,sizeof(struct ActionNode));
  450.       }
  451.       if(dp->dp_Type == ACTION_WRITE) {
  452.         dp->dp_Res1 = -1;
  453.         goto nomem2;
  454.       }
  455.       break;
  456.     case ACTION_SEEK:
  457.       dp->dp_Res1 = -1;
  458.       dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  459.       rport = dp->dp_Port;
  460.       dp->dp_Port = ci->ci_Handler;
  461.       PutMsg(rport,dp->dp_Link);
  462.       return;
  463.     case ACTION_WAIT_CHAR:
  464.     case ACTION_SCREEN_MODE:
  465.     case 2004: /* ACTION_DROP */
  466.       an = (struct ActionNode *)AllocMem(sizeof(struct ActionNode),0);
  467.       if(an) {
  468.         trans = AllocTransaction(TRN_AllocReqBuffer,
  469.                                  OFFS_REQDATA,
  470.                                  TRN_AllocRespBuffer,
  471.                                  OFFS_RESPDATA,
  472.                                  TAG_DONE);    
  473.         if(trans) {
  474.           *(LONG *)req(trans,OFFS_ARG1) = dp->dp_Type;
  475.           *(LONG *)req(trans,OFFS_ARG2) = dp->dp_Arg1;
  476.           BeginTransaction(ci->ci_Dest,ci->ci_Source,trans);
  477.           an->an_Trans = trans;
  478.           an->an_Packet = dp;
  479.           AddTail((struct List *)&(ci->ci_Actions),(struct Node *)an);
  480.           return;
  481.         }
  482.         FreeMem(an,sizeof(struct ActionNode));
  483.       }
  484.       break;
  485.     case ACTION_CHANGE_SIGNAL:
  486.       dp->dp_Res1 = DOSTRUE;
  487.       dp->dp_Res2 = (LONG)(ci->ci_Break);
  488.       if(dp->dp_Arg2) {
  489.         ci->ci_Break = (struct MsgPort *)dp->dp_Arg2;
  490.       }
  491.       rport = dp->dp_Port;
  492.       dp->dp_Port = ci->ci_Handler;
  493.       PutMsg(rport,dp->dp_Link);
  494.       return;
  495.     case ACTION_DISK_INFO:
  496.       if(ci->ci_IOStdReq) {
  497.         struct InfoData *id;
  498.         ULONG i;
  499.  
  500.         id = (struct InfoData *)BADDR(dp->dp_Arg1);
  501.         for(i = 0;i < sizeof(struct InfoData);i++) ((UBYTE *)id)[i] = 0;
  502.         id->id_InUse = (LONG)(ci->ci_IOStdReq);
  503.         dp->dp_Res1 = DOSTRUE;
  504.         rport = dp->dp_Port;
  505.         dp->dp_Port = ci->ci_Handler;
  506.         PutMsg(rport,dp->dp_Link);
  507.         return;
  508.       }
  509.     default:
  510.       dp->dp_Res1 = DOSFALSE;
  511.       dp->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  512.       rport = dp->dp_Port;
  513.       dp->dp_Port = ci->ci_Handler;
  514.       PutMsg(rport,dp->dp_Link);
  515.       return;
  516.   }
  517.   dp->dp_Res1 = DOSFALSE;
  518. nomem2:
  519.   dp->dp_Res2 = ERROR_NO_FREE_STORE;
  520.   rport = dp->dp_Port;
  521.   dp->dp_Port = ci->ci_Handler;
  522.   PutMsg(rport,dp->dp_Link);
  523. }
  524.  
  525. void do_transaction(struct Library *NIPCBase,
  526.                     struct ConInfo *ci,
  527.                     struct Transaction *trans)
  528.  
  529. {
  530.   struct ActionNode *an;
  531.   struct DosPacket *dp;
  532.  
  533.   debug3("Transaction: Type: %ld, Com: %ld\n",trans->trans_Type,
  534.          trans->trans_Command);
  535.  
  536.   if(trans->trans_Type != TYPE_RESPONSE) {
  537.     if(trans->trans_Command > 15) {
  538.       trans->trans_Error = ENVOYERR_CMDUNKNOWN;
  539.     }
  540.     else {
  541.       debug2("BREAK: %ld\n",trans->trans_Command);
  542.       if((ci->ci_Break->mp_Flags & PF_ACTION) == PA_SIGNAL) {
  543.         Signal(ci->ci_Break->mp_SigTask,((ULONG)(trans->trans_Command))<<12);
  544.         debug("BREAK done\n");
  545.       }
  546.     }
  547.     ReplyTransaction(trans);
  548.   }
  549.   else {
  550.     an = (struct ActionNode *)(ci->ci_Actions.mlh_Head);
  551.     while(an->an_Node.mln_Succ) {
  552.       if(an->an_Trans == trans) break;
  553.       an = (struct ActionNode *)(an->an_Node.mln_Succ);
  554.     }
  555.     if(an->an_Node.mln_Succ) {
  556.       dp = an->an_Packet;
  557.       if(trans->trans_Error) {
  558.         if(dp->dp_Type == ACTION_READ || dp->dp_Type == ACTION_WRITE) {
  559.           dp->dp_Res1 = -1;
  560.         }
  561.         else {
  562.           dp->dp_Res1 = DOSFALSE;
  563.         }
  564.         dp->dp_Res2 = ERROR_NO_FREE_STORE;
  565.       }
  566.       else {
  567.         if(ci->ci_IOStdReq) {
  568.           CopyMem(resp(trans,OFFS_CONUNIT),CONUNIT(ci),SIZE_CONUNIT);
  569.         }
  570.         dp->dp_Res1 = *(LONG *)resp(trans,OFFS_RES1);
  571.         dp->dp_Res2 = *(LONG *)resp(trans,OFFS_RES2);
  572.         if(dp->dp_Type == ACTION_READ && dp->dp_Res1 > 0) {
  573.           CopyMem(resp(trans,OFFS_RESPDATA),(APTR)(dp->dp_Arg2),dp->dp_Res1);
  574.         }
  575.       }
  576.       ci->ci_Break = dp->dp_Port;
  577.       dp->dp_Port = ci->ci_Handler;
  578.       PutMsg(ci->ci_Break,dp->dp_Link);
  579.       Remove((struct Node *)an);
  580.       FreeMem(an,sizeof(struct ActionNode));
  581.     }      
  582.     FreeTransaction(trans);
  583.   }
  584. }
  585.